package user

import (
	"context"
	"gfDemo/internal/dao"
	"gfDemo/internal/model"
	"gfDemo/internal/model/do"
	"gfDemo/internal/model/entity"
	"gfDemo/internal/service"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/errors/gerror"
)

type (
	sUser struct{}
)

func init() {
	service.RegisterUser(&sUser{})
}

// Create 创建用户
func (s *sUser) Create(ctx context.Context, in model.UserCreateInput) (err error) {
	if in.Nickname == "" {
		in.Nickname = in.Passport
	}
	var (
		available bool
	)
	available, err = s.IsPassportAvailable(ctx, in.Passport)
	if err != nil {
		return
	}
	if !available {
		return gerror.Newf(`护照 "%s" 已被占用`, in.Passport)
	}

	available, err = s.IsNicknameAvailable(ctx, in.Password)
	if err != nil {
		return
	}
	if !available {
		return gerror.Newf(`昵称 "%s" 已被占用`, in.Passport)
	}

	return dao.User.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		_, err = dao.User.Ctx(ctx).Data(do.User{
			Passport: in.Passport,
			Password: in.Password,
			Nickname: in.Nickname,
		}).Insert()
		return err
	})
}

// IsSignedIn 当前是否已经登录
func (s *sUser) IsSignedIn(ctx context.Context) bool {
	if v := service.BizCtx().Get(ctx); v != nil && v.User != nil {
		return true
	}
	return false
}

// SignIn 登录账号提供session
func (s *sUser) SignIn(ctx context.Context, in model.UserSignInInput) (err error) {
	var user *entity.User
	err = dao.User.Ctx(ctx).Where(do.User{
		Passport: in.Passport,
		Password: in.Password,
	}).Scan(&user)
	if err != nil {
		return err
	}
	if user == nil {
		return gerror.New(`Passport or Password not correct`)
	}
	if err = service.Session().SetUser(ctx, user); err != nil {
		return err
	}
	service.BizCtx().SetUser(ctx, &model.ContextUser{
		Id:       user.Id,
		Passport: user.Passport,
		Nickname: user.Nickname,
	})
	return nil
}

// SignOut 退出登录
func (s *sUser) SignOut(ctx context.Context) error {
	return service.Session().RemoveUser(ctx)
}

func (s *sUser) IsPassportAvailable(ctx context.Context, passport string) (pass bool, err error) {
	var count int
	count, err = dao.User.Ctx(ctx).Where(do.User{
		Passport: passport,
	}).Count()
	if err != nil {
		return
	}
	return count == 0, nil
}

func (s *sUser) IsNicknameAvailable(ctx context.Context, nickname string) (pass bool, err error) {
	var count int
	count, err = dao.User.Ctx(ctx).Where(do.User{
		Nickname: nickname,
	}).Count()
	if err != nil {
		return
	}
	return count == 0, nil
}

func (s *sUser) GetProfile(ctx context.Context) *entity.User {
	return service.Session().GetUser(ctx)
}
